package com.bitbakery.plugin.lisp.lang.psi;

import com.bitbakery.plugin.lisp.LispIcons;
import com.bitbakery.plugin.lisp.lang.LispElementVisitor;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

public class CLDefun extends CLElement implements PsiNamedElement {
    public CLDefun(ASTNode node) {
        super(node);
    }

    public CLFormalParameterList getFormalParameterList() {
        return (CLFormalParameterList) getNode().findChildByType(CLElementTypes.FORMAL_PARAMETER_LIST).getPsi();
    }

    public ASTNode getBody() {
        return getNode().findChildByType(CLElementTypes.FUNCTION_BODY);
    }

    public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
        final ASTNode functionName = findName();
        // TODO - Something...?
        return this;
    }

    @Nullable
    @NonNls
    public String getName() {
        return getText(findName());
    }

    public String getDocstring() {
        return getText(getNode().findChildByType(CLElementTypes.DOCSTRING));
    }


    public int getTextOffset() {
        final ASTNode name = findName();
        return name != null ? name.getStartOffset() : super.getTextOffset();
    }

    public boolean processDeclarations(PsiScopeProcessor processor,
                                       PsiSubstitutor substitutor,
                                       PsiElement lastParent,
                                       PsiElement place) {
/*
        if (lastParent != null && lastParent.getParent() == this) {
            final CommonLispParameter[] params = getFormalParameterList().getParameters();
            for (CommonLispParameter param : params) {
                if (!processor.execute(param, substitutor)) return false;
            }
        }
*/

        return processor.execute(this, substitutor);
    }

    public void accept(@NotNull PsiElementVisitor visitor) {
        if (visitor instanceof LispElementVisitor) {
            ((LispElementVisitor) visitor).visitCommonLispFunctionDefinition(this);
        } else {
            visitor.visitElement(this);
        }
    }

    public String toString() {
        return "CLDefun";
    }

    public Icon getIcon(int flags) {
        return LispIcons.COMMON_LISP_DEFUN_NODE;
    }

    private String getText(ASTNode node) {
        return node != null ? node.getText() : null;
    }

    private ASTNode findName() {
        return getNode().findChildByType(CLElementTypes.FUNCTION_NAME);
    }
}
